package com.stottlerhenke.simbionic.editor.gui;

import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.List;
import java.util.Vector;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.DefaultCellEditor;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.tree.DefaultMutableTreeNode;

import com.stottlerhenke.simbionic.api.SB_Exception;
import com.stottlerhenke.simbionic.common.parser.EParseFlags;
import com.stottlerhenke.simbionic.common.parser.SB_ExpressionNode;
import com.stottlerhenke.simbionic.editor.SB_Binding;
import com.stottlerhenke.simbionic.editor.SB_Global;
import com.stottlerhenke.simbionic.editor.SB_Parameter;
import com.stottlerhenke.simbionic.editor.SB_Variable;
import com.stottlerhenke.simbionic.editor.SimBionicEditor;
import com.stottlerhenke.simbionic.editor.common.CopyAndPasteAdapter;
import com.stottlerhenke.simbionic.editor.parser.SB_ArrayNode;
import com.stottlerhenke.simbionic.editor.parser.SB_ErrorNode;
import com.stottlerhenke.simbionic.editor.parser.SB_ParseNode;
import com.stottlerhenke.simbionic.editor.parser.SB_ParserEditorInterface;

/**
 * This class implements a dialog for setting the value of a table or an array
 * The button that trigger this dialog is located within the EditBinding Dialog
 * The dialog allows setting of the table size and set the table entry values.
 * (or array)
 * 
 *
 */
public class SetValueDialog extends StandardDialog 
implements TableModelListener {

	public static String TITLE = "Initial Table Value";
	public static String ARRAY_TITLE = "Initial Array Value";
	public static String ROW_LABEL = "Number of rows:";
	public static String COLUMN_LABEL = "Number of columns:";
	public static String RESIZE_LABEL = "Resize";
	public static String QUOTE_CELLS_LABEL = "Enclose in quotes";
	
	public static int DEFAULT_ROW_NUMBER = 10;
	public static int DEFAULT_COL_NUMBER = 1;
	
	public static String DEFAULT_ERROR_MESSAGE = "Error setting expression.";
		
	protected JTextField _rowTextField;
	protected JTextField _columnTextField;
	protected JTable _table;
	protected SetValueTableModel _tableModel;
	protected SimBionicEditor _editor;
	protected SB_Binding _binding;
	protected boolean _isArray;
	protected SB_Polymorphism _poly;
		 
	/**
	 * Constructor
	 * @param editor SimBionicEditor needed to create SB_Autocomplete
	 * @param isArray is this dialog for editing array?
	 */
    public SetValueDialog(SimBionicEditor editor, boolean isArray)
    {
    	super(ComponentRegistry.getFrame());
    	_editor = editor; // needed to create SB_Autocomplete
    	_poly = null; // needed for check parsing
    		
    	_isArray = isArray;
    	if(!isArray){
    		this.setTitle(TITLE);
    	} else {
    		this.setTitle(ARRAY_TITLE);
    	}
    	// must go before initGUI;
    	if(isArray){
    		_tableModel = new SetArrayValueTableModel();
    	} else {
    		_tableModel = new SetValueTableModel();
    	}
    	initGUI();
    	this.setModal(true); // this dialog should be modal
    }

 
    protected void initGUI(){
        JPanel editPanel = new JPanel();

        editPanel.setLayout(new BoxLayout(editPanel, BoxLayout.Y_AXIS));
        editPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
        editPanel.add(createResizePanel());
        
        // setup table
        _table = new JTable(_tableModel);
        SB_Autocomplete _expressionEditor = _editor.createAutocomplete();
        _table.setDefaultEditor(String.class, new DefaultCellEditor(_expressionEditor));
        _table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);

        JScrollPane scroller = new javax.swing.JScrollPane(_table);
         _table.setPreferredScrollableViewportSize(new java.awt.Dimension(500, 300));
         editPanel.add(scroller);
        _tableModel.addTableModelListener(this);

        // to allow cell selections
        _table.setRowSelectionAllowed(true); 
        _table.setColumnSelectionAllowed(true);
        CopyAndPasteAdapter copyAndPasteAdapter = new CopyAndPasteAdapter(_table);
        
        // context menu
        final JPopupMenu popup = new JPopupMenu();
        JMenuItem menuItem = new JMenuItem(QUOTE_CELLS_LABEL);
        menuItem.addActionListener(new QuoteSelectedCellsListener()); 
        popup.add(menuItem);
        
        MouseListener popupListener = new MouseAdapter() {
        	public void mousePressed(MouseEvent e) {
        		if (e.isPopupTrigger()) {
        			popup.show(e.getComponent(), e.getX(), e.getY());
        		}
        	}
        	
        	public void mouseReleased(MouseEvent e) {
        		if (e.isPopupTrigger()) {
        			popup.show(e.getComponent(), e.getX(), e.getY());
        		}
        	}
        };
        _table.addMouseListener(popupListener);
        
        initDialog(editPanel, null);
        
    }
    
    /**
     * create the panel for resizing the table
     * @return JPanel containing the UI needed to resize the table
     */
    protected JPanel createResizePanel(){
        // for row
        JPanel resizePanel = new JPanel(new GridBagLayout());
        GridBagConstraints constraint = new GridBagConstraints();
        constraint.insets = new Insets(5, 5, 5, 5); 
        constraint.gridx=0; constraint.gridy=0; 
        JLabel label = new JLabel(ROW_LABEL);
        resizePanel.add(label, constraint);
        // create the textfield and the resize button
        // the textfield
        _rowTextField = new JTextField(10);
        _rowTextField.setText(String.valueOf(DEFAULT_ROW_NUMBER));
        _rowTextField.setMaximumSize(new Dimension(100, 20));
        _rowTextField.setAlignmentX(Component.LEFT_ALIGNMENT);
        constraint.gridx=1; 
        resizePanel.add(_rowTextField, constraint);
        // button
        JButton resizeButton = new JButton(RESIZE_LABEL);
        resizeButton.addActionListener(new ActionListener(){
        	public void actionPerformed(ActionEvent e){
        		int row = Integer.parseInt(_rowTextField.getText());
        		if(!_isArray){
        			int col = Integer.parseInt(_columnTextField.getText());
        			_tableModel.setTableSize(row, col);
        		} else {
        			_tableModel.setTableSize(row, 1);
        		}
        	}
        });
        constraint.gridx=2; 
        resizeButton.setFocusPainted(false);
        resizePanel.add(resizeButton, constraint);

        // column
        if(!_isArray){
	        JLabel colLabel = new JLabel(COLUMN_LABEL);
	        constraint.gridx=0; 
	        constraint.gridy++; 
	        resizePanel.add(colLabel, constraint);
	        // create the textfield 
	        _columnTextField = new JTextField(10);
	        _columnTextField.setText(String.valueOf(DEFAULT_COL_NUMBER));
	        _columnTextField.setMaximumSize(new Dimension(100, 20));
	        _columnTextField.setAlignmentX(Component.LEFT_ALIGNMENT);
	        constraint.gridx=1;
	        resizePanel.add(_columnTextField, constraint);
        }
        return resizePanel;
    }
    
    /**
     * to be called to initialize the dialog. the table value will be reset
     * @param binding SB_binding containing the value to be set.
     */
    public void initDialog(SB_Binding binding, SB_Polymorphism poly){
    	_binding = binding;
        _tableModel.setValue(binding.getExpr());
    	// needed to parse variable names
        _poly = poly;
        SB_ParserEditorInterface.getParser().setPoly(poly);
    }
    
   @Override
    public void onOk(){
    	super.onOk();
    	if(_binding!=null){
    		_binding.setExpr(_tableModel.getValue());
    	}
    }
    
   @Override
    public void tableChanged(TableModelEvent e)
    { 
    	_table.revalidate();
    	repaint();
    }
    
    /**
     * A Table Model that uses Vector of Vectors to store the data of
     * a table
     *
     */
    class SetValueTableModel extends AbstractTableModel {

    	protected Vector _data; // Vector of Vectors
    	
    	/**
    	 * Constructor
    	 *
    	 */
    	public SetValueTableModel(){
   			_data = createDefaultTable();
    	}
    	
    	/**
    	 * create a default empty table of size DEFAULT_ROW_NUMBER by DEFAULT_COL_NUMBER
    	 * @return table a Vector of Vectors representing the table
    	 */
    	protected Vector createDefaultTable(){
    		Vector table = new Vector(DEFAULT_ROW_NUMBER);
    		table.setSize(DEFAULT_ROW_NUMBER);
    		for(int i=0;i<DEFAULT_ROW_NUMBER;i++){
    			Vector aRow = new Vector(DEFAULT_COL_NUMBER);
    			aRow.setSize(DEFAULT_COL_NUMBER);
    			table.set(i, aRow);
    		}
    		return table;
    	}

    	
    	@Override
        public int getColumnCount() {
        	// data size plus one to account for the label column
        	if(_isArray){
        		return 2;
        	}
        	if(_data.size()==0){
        		return 1;
        	}
        	// just in case
        	if(! (_data.get(0) instanceof Vector)){
        		return 2;
        	}
            return ((Vector)_data.get(0)).size()+1;
        }

    	@Override
        public int getRowCount() {
        	return _data.size();
        }

        /**
         * The column name would be the column index of the table
         */
    	@Override
        public String getColumnName(int col) {
            if(col==0){ // column of the row index
            	//need to put something here o.w. the header will be too narrow
            	return String.valueOf(" ");
            }
            return String.valueOf(col-1);
        }

    	/**
    	 * reset the size of the table (data)
    	 * @param row new row size
    	 * @param col this value
    	 */
        public void setTableSize(int row, int col){
        	
            _data.setSize(row);
        	for(int i=0;i<row;i++){
        		Object aRow = _data.get(i);
        		if(aRow==null){
        			aRow = new Vector(col);
        			_data.set(i, aRow);
        		}
        		((Vector)aRow).setSize(col);
        	}

           	_columnTextField.setText(String.valueOf(col));
           	_rowTextField.setText(String.valueOf(row));
        	this.fireTableStructureChanged();
        	// needed to set the row label again
            _table.getColumnModel().getColumn(0).setCellRenderer(new LabelRenderer());             
        }
        
        @Override
        public Object getValueAt(int row, int col) {
        	// label column
        	if(col==0){
        		return String.valueOf(row);
        	}
        	
        	col--; // index for the data
        	if(_data.size()==0 || _data.size()<=row){
        		return null; // error
        	}
        	if(! (_data.get(row) instanceof Vector)){
        		return _data.get(row) ;
        	}
        	Vector currentRow = (Vector)_data.get(row);
            if (currentRow.size()== 0 || currentRow.size()<=col){
            	return null;
            }
            return currentRow.get(col);
        }

        /**
         * TODO: Improve exception/error reporting
         * 
         * Set the table value at (row, col)
         * @param value value to be set
         * @param row index of table
         * @param col index of table (not the index in data)
         */
        public void setValueAt(Object value, int row, int col) {
        	if(col==0){ // no need to set value for header
        		return;
        	}
        	col--; // convert to index of data
        	if(_data.size()==0 || _data.size()<=row){
        		// error
        		return;
        	}
        	if(! (_data.get(row) instanceof Vector)){
        		return;
        	}

        	// should pop up warning if the expression is not allowed.
        	if(!(value instanceof String)){
        		return; // error
        	}
      
        	// check if the value is an expression
        	// if yes, proceed to set value, 
        	// else, try to parse the value and check if the expression is valid
        	// if the check fails, shows an error dialog but still set the value.
        	// (which is the current C++ version behavior)
            try{
            	// if the value is null, just set it, do not need to check using parser
               	if(value!=null && !"null".equals(value))
               	{
               		SB_ExpressionNode node = SB_ParserEditorInterface.getParser().Parse((String)value);
               		if(node instanceof SB_ErrorNode){
               			SB_ErrorNode errorNode = (SB_ErrorNode)node;
               			// TODO: unable to show the dialog
               			// since this will hang the program on specific operations
               			// will try to will Custom built dialog
               			//JOptionPane.showMessageDialog(SetValueDialog.this, "Error: "+errorNode.GetMsg());
               		} 
                	// the following check of is variable name is actually not needed
                	// because the check is taken care of by the Parser
                	// however, in subclass SetInitialValueDialog
                	// initial global value should not contain local/param variable
                	// isVarName provided this extra checking
               		// current this check is truned off to match the behavior in C++ version
               		//else if(node instanceof SB_VariableNode){
               			// if(!isVarName((String)value)){
               			// warning message
               			//}
               		//}
               	}
            } catch (Exception e){
            	//JOptionPane.showMessageDialog(SetValueDialog.this, DEFAULT_ERROR_MESSAGE);
            }

        	Vector currentRow = (Vector) _data.get(row);
        	if(value!=null && "null".equals(value)){
        		currentRow.set(col, null); // special treatment of null value. null is input as String "null"
        	} else {
        		currentRow.set(col, value);
        	}
        	col++;
        	fireTableCellUpdated(row, col);
        }
        
        /**
         * return the class of the column
         * @param c index of the column
         */
        public Class getColumnClass(int c) {
        	if(c==0){
        		return JLabel.class;
        	}
            return String.class;
        }
        
        @Override
        public boolean isCellEditable(int row, int col) {
        	if(col==0){ // dont edit the label column
        		return false;
        	}
            return true;
        }
        
        /**
         * get the String representation of this table value
         * @return value  String representation of this table value
         */
        public String getValue(){
        	// it would be tricky to use SB_Param.toSerializeString();
        	// so we will write our own parser here
        	return tableToString(_data);
        }
    	
        /**
         * Get the string representation for this table value
         * @param table input table
         * @return  string representation for this table value
         */
        protected String tableToString(Vector table)
        {
        	StringBuffer buff = new StringBuffer();
            int nCount = table.size();
            
            if( nCount == 0 ){
              buff.append("{}");
            } else
            {
    	        for( int x = 0; x < nCount; x++ )
    	        {
    	          if( x == 0 )
    	            buff.append("{");
    	          else
    	            buff.append(", ");

    	          buff.append(arrayToString( (Vector)table.get(x)));
    	          if( x == (nCount - 1) )
    	            buff.append("}");
    	        }
            }
           return buff.toString();
        }
        
        /**
         * Set the value of the table using the given String expression
         * @param expr input String expression value
         */
    	public void setValue(String expr){
    		// convert the expression 'expr'
    		// to the representation of an Vector
    		_data = StringToTable(expr);
    		// need to set text field too
    		int maxColSize=0;
    		for(int i=0;i<getRowCount();i++){
    			int colSize = ((Vector)_data.get(i)).size();
    			if(maxColSize<colSize){
    				maxColSize = colSize;
    			}
    		}
    		setTableSize(getRowCount(), maxColSize);
    	}
    	
        /**
         * get the String representation of this table value
         * @return value  String representation of this table value
         * @param expr
         * @return
         */
        protected Vector StringToTable(String expr){
        	if(expr==null || "".equals(expr)){
        		return createDefaultTable(); // if expr is empty, use the default
        	}
        	// parse the expr
        	SB_ExpressionNode node = null;
        	List list = null;
        	Vector newVector = new Vector();
    		newVector.setSize(0);
        	try{
        		node = SB_ParserEditorInterface.getParser().Parse(expr, EParseFlags.kNoFlag);

              	SB_ArrayNode array = (SB_ArrayNode)node;
              	list = array.getArray();
        	} catch (Exception e){
        		return createDefaultTable(); // if expr is empty, use the default
        	}

        	if(list == null || list.size()==0){
        		return newVector;
        	}
        	int rowSize = list.size();
        	newVector.setSize(rowSize);
        	// set up each row
        	try{
	        	for(int i=0;i<rowSize;i++){
	        		newVector.set(i, ArrayNodeToVector(list.get(i)));
	        	}
	     	} catch (Exception e){
	    		return createDefaultTable(); // if expr is empty, use the default
	    	}
        	return newVector;
        }
        
        /**
         * returns true if the given string is a variable name
         * @param varName given string to check if it is a variable
         * @return true if the given string is a variable name
         */
        protected boolean isVarName(String varName){
        	return isVariable(varName);
        }

    }
    
    /**
     * A Table Model that uses a Vector to store the data for an Array
     * @author bwong
     *
     */
    class SetArrayValueTableModel extends SetValueTableModel {
    	
    	/**
    	 * Constructor
    	 *
    	 */
    	public SetArrayValueTableModel(){
    		_data = createDefaultArray();
    	}
    	
    	/**
    	 * create a default empty array of size DEFAULT_ROW_NUMBER
    	 * @return Array a Vector of representing the array
    	 */
    	protected Vector createDefaultArray(){
    		Vector array = new Vector(DEFAULT_ROW_NUMBER);
    		array.setSize(DEFAULT_ROW_NUMBER);
    		return array;
    	}
    	
    	/**
    	 * reset the size of the array
    	 * @param row new row size
    	 * @param col this value is ignored
    	 */
        public void setTableSize(int row, int col){
        	//if(row!=0){
            _data.setSize(row);
        	this.fireTableStructureChanged();
        	// needed to set the row label again
        	_rowTextField.setText(String.valueOf(row));
            _table.getColumnModel().getColumn(0).setCellRenderer(new LabelRenderer());             
        }
        
        @Override
        public Object getValueAt(int row, int col) {
        	// label column
        	if(col==0){
        		return String.valueOf(row);
        	}
        	col--; // index for the data
        	if(_data.size()==0 || _data.size()<=row || col>1){
        		return null; // error
        	}
       		return _data.get(row);
        }

        /**
         * TODO: Improve error/exception reporting.
         * 
         * Set the table value at (row, col)
         * @param value value to be set
         * @param row index of table
         * @param col index of table (not the index in data)
         */
        public void setValueAt(Object value, int row, int col) {
        	if(col==0){ // no need to set value for header
        		return;
        	}
        	if(_data.size()==0 || _data.size()<=row || col>1){
        		return; // error
        	}
        	
        	// check if the value is an expression
        	// if yes, proceed to set value, 
        	// else, try to parse the value and check if the expression is valid
        	// if the check fails, shows an error dialog but still set the value.
        	// (which is the current C++ version behavior)
           	try{
           		//this is by default using flag EParseFlags.kNoFlag
           		SB_ExpressionNode node = SB_ParserEditorInterface.getParser().Parse((String)value);
           		if(node instanceof SB_ErrorNode){
           			SB_ErrorNode errorNode = (SB_ErrorNode)node;
           			// TODO: unable to show the dialog
           			// since this will hang the program on specific operations
           			// will try to will Custom built dialog
           			//JOptionPane.showMessageDialog(SetValueDialog.this, "Error: "+errorNode.GetMsg());
           			
           		}
               	// the following check of is variable name is actually not needed
               	// because the check is taken care of by the Parser
               	// however, in subclass SetInitialValueDialog
               	// initial global value should not contain local/param variable
               	// isVarName provided this extra checking
             	// current this check is truned off to match the behavior in C++ version
             	//else if(node instanceof SB_VariableNode){
              		// if(!isVarName((String)value)){
              		// warning message
               		//}
               	//}
            } catch (Exception e){
            	//JOptionPane.showMessageDialog(SetValueDialog.this, DEFAULT_ERROR_MESSAGE);
            	//C++ version still allows typing in of invalid values
        	}
        	_data.set(row, value);
        	fireTableCellUpdated(row, col);
        	
        }
       
        /**
         * get the String representation of this table value
         * @return value  String representation of this table value
         */
        public String getValue(){
        	// it would be tricky to use SB_Param.toSerializeString();
        	// so we will write our own parser here
        	return arrayToString(_data);
        }
        
        /**
         * Set the value of the table using the given String expression
         * @param expr input String expression value
         */
    	public void setValue(String expr){
    		// convert the expression 'expr'
    		// to the representation of an Vector
    		_data = StringToArray(expr);
    		// need to set text field too
    		if(_data!=null){
    			setTableSize(_data.size(), 1);
   			} else {
   				setTableSize(0, 1);
   			}
    	}
    	
        /**
         * get the String representation of this table value
         * @return value  String representation of this table value
         * @param expr
         * @return
         */
        protected Vector StringToArray(String expr){
        	if(expr==null || "".equals(expr)){
        		return createDefaultArray(); // if expr is empty, use the default
        	}
        	// parse the expr
        	SB_ExpressionNode node = null;
        	Vector newVector = new Vector();
    		newVector.setSize(0);
        	try{
        		node = SB_ParserEditorInterface.getParser().Parse(expr);
        		if(node instanceof SB_ErrorNode){
        			return createDefaultArray(); // if expr is empty, use the default
        		}
        		return ArrayNodeToVector(node);
        	} catch (Exception e){
        		return createDefaultArray(); // if expr is empty, use the default
        	}
        }
        
    }
    
    /**
     * convert the given SB_ArrayNode to a Vector
     * if the given object is not an SB_ArrayNode 
     * This function is used in both table model
     * @param node
     * @return
     * @throws SB_Exception
     */
	protected Vector ArrayNodeToVector(Object node) throws SB_Exception {
		Vector v = new Vector();
 		v.setSize(0);
 		// not a valid node
 		if(node==null || !(node instanceof SB_ArrayNode)){
 			return v;
 		}
 		List list = ((SB_ArrayNode)node).getArray();
 		if(list!=null){
 			v.setSize(list.size());
        	for(int i=0;i<list.size();i++){
        		Object item = (SB_ParseNode)list.get(i);
        		if(item != null && item instanceof SB_ParseNode){
        			v.set(i, ((SB_ParseNode)item).ToString());	        		
        		}
        	}
 		}
 		return v;
	}
	
	


    /**
     * Return a string representation of an array.
     * Since each element of the table is 
     * This method is called in both TableModel
     * @param array input array
     * @return a string representation of this array.
     */
    protected String arrayToString(Vector array)
    {
    	StringBuffer buff = new StringBuffer();
        int nCount = array.size();
        if( nCount == 0 ){
          buff.append("{}");
        } else
        {
	        for( int x = 0; x < nCount; x++ )
	        {
	          if( x == 0 ){
	            buff.append("{");
	          } else {
	            buff.append(", ");
	          }
	          if(array.get(x)==null){
	        	  buff.append(" "); // seems like it's the convention
	          } else {
	        	  buff.append(array.get(x));
	          }
	          if( x == (nCount - 1) )
	            buff.append("}");
	        }
        }
       return buff.toString();
    }

    /**
     * returns true if the given string is a variable name
     * @param varName given string to check if it is a variable
     * @return true if the given string is a variable name
     */
    protected boolean isVariable(String varName){
    	return (isParam(varName) || isLocal(varName) || isGlobal(varName));
    }
    
    /**
     * returns true if the given string is a global variable name
     * @param varName given string to check if it is a global variable
     * @return true if the given string is a global variable name
     */
    protected boolean isGlobal(String varName){
        DefaultMutableTreeNode globals = _editor.getCatalog()._globals;
        int GlobalSize = globals.getChildCount();
        for (int i = 0; i < GlobalSize; ++i) {
            SB_Global global = (SB_Global) ((DefaultMutableTreeNode) globals.getChildAt(i)).getUserObject();
            if(global.getName().equals(varName)){
            	return true;
            }
        }
        return false;
    }
    /**
     * returns true if the given string is a param variable name
     * @param varName given string to check if it is a param variable
     * @return true if the given string is a param variable name
     */
    protected boolean isParam(String varName){
        SB_Catalog catalog = _editor.getCatalog(); //projectBar._catalog;
    	SB_Polymorphism poly = _poly;
        DefaultMutableTreeNode params = catalog.findNode(poly._parent, catalog._behaviors);
        int paramSize = params.getChildCount();
        for (int i = 0; i < paramSize; ++i) {
            SB_Parameter param = (SB_Parameter) ((DefaultMutableTreeNode) params.getChildAt(i)).getUserObject();
            if(param.getName().equals(varName)){
            	return true;
            }
        }
        return false;
    }
    
    /**
     * returns true if the given string is a local variable name
     * @param varName given string to check if it is a local variable
     * @return true if the given string is a local variable name
     */
    protected boolean isLocal(String varName){
        // check local variable (code similar to SetBinding)
    	SB_Polymorphism poly = _poly;
        DefaultMutableTreeNode locals = poly._locals;
        int localSize = locals.getChildCount();
        for(int k=0;k<localSize;k++){
        	SB_Variable local = (SB_Variable) ((DefaultMutableTreeNode) locals.getChildAt(k)).getUserObject();
        	if(local.getName().equals(varName)){
        		return true;
        	}
        }
        return false;
    }
    /**
     * A renderer for the rendering the first column label of the table
     */
    public class LabelRenderer extends JLabel implements TableCellRenderer {
    	 
    	/**
    	 * Constructor
    	 */
    	  public LabelRenderer() {
    	    setOpaque(true);
    	  }
    	  
    	  /*
    	   *  (non-Javadoc)
    	   * @see javax.swing.table.TableCellRenderer#getTableCellRendererComponent(javax.swing.JTable, java.lang.Object, boolean, boolean, int, int)
    	   */
    	  public Component getTableCellRendererComponent(JTable table, Object value,
    	                   boolean isSelected, boolean hasFocus, int row, int column) {
    	    if (isSelected) {
    	      setForeground(table.getSelectionForeground());
    	      setBackground(table.getSelectionBackground());
    	    } else{
    	      setForeground(table.getForeground());
    	      setBackground(UIManager.getColor("Button.background"));
    	    }
    	    setText( String.valueOf(row)); // row label
    	    return this;
    	  }
    }
    
    private class QuoteSelectedCellsListener implements ActionListener {
    	public void actionPerformed(ActionEvent arg0) {
    		SetValueDialog.this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
    		for (int i = 0; i < _tableModel.getRowCount(); i++) {
				for (int j = 0; j < _tableModel.getColumnCount(); j++) {
					if (_table.isCellSelected(i, j)) {
						Object val = _tableModel.getValueAt(i, j);
						if (val instanceof String) {
							String valStr = (String)val;
							if (!(valStr.startsWith("\"") && valStr.endsWith("\""))) {
								_tableModel.setValueAt("\"" + valStr + "\"", i, j);
							}
						} else if (val == null) {
							_tableModel.setValueAt("\"\"", i, j);
						}
					}
				}
			}
    		SetValueDialog.this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
    	}
    }

}
